﻿using System;
using System.Linq.Expressions;

namespace Hvam.SharePoint.Search.Language.Visitors
{
    internal abstract class ExpressionVisitor
    {
        protected virtual Expression Visit(Expression expression)
        {
            if (expression == null)
            {
                return null;
            }

            switch (expression.NodeType)
            {
                case ExpressionType.Constant:
                    return VisitConstant((ConstantExpression) expression);
                case ExpressionType.And:
                case ExpressionType.Or:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.Equal:
                case ExpressionType.NotEqual:
                    return VisitBinary((BinaryExpression) expression);
                case ExpressionType.Call:
                    return VisitMethodCall((MethodCallExpression) expression);
                default:
                    throw new Exception(string.Format("Unhandled expression type: '{0}'", expression.NodeType));
            }
        }

        protected virtual Expression VisitBinary(BinaryExpression binaryExpression)
        {
            var left = Visit(binaryExpression.Left);
            var right = Visit(binaryExpression.Right);
            if (left != binaryExpression.Left || right != binaryExpression.Right)
            {
                return Expression.MakeBinary(binaryExpression.NodeType, left, right, binaryExpression.IsLiftedToNull, binaryExpression.Method);
            }
            return binaryExpression;
        }

        protected virtual Expression VisitConstant(ConstantExpression constantExpression)
        {
            return constantExpression;
        }

        protected virtual Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            return methodCallExpression;
        }
    }
}
